package org.testis.testdriver.validation;

import org.testis.data.TestStepDataObject;
import org.testis.testdriver.*;
import org.testis.testdriver.AtofEnumaration.AtofLogLevel;
import org.testis.testdriver.AtofEnumaration.DebuggingMode;
import org.testis.testdriver.exceptions.ImpossibleToAchieveSuccessPercentageException;
import org.testis.testdriver.resultsmatrix.ThreeDResultsMatrix;
import com.mallardsoft.tuple.Pair;

/**
 *
 * @author barisergun
 */
public class TestPartValidateTestStepGroupStrategy extends TestPartValidateStrategy {

    public TestPartValidateTestStepGroupStrategy(TestPart inUse) {
        super(inUse);
    }

    @Override
    public boolean validateFinalPartResult(TestIterator testIterInRun,
            DebuggingMode mode,
            boolean partResult) {

        StepContainer stepGroupContainer = (StepContainer) testPartInRun;
        String tsgGuid = stepGroupContainer.getPartGuid()
                + stepGroupContainer.getParent().
                getPartGuidLongFromChild().replaceAll(stepGroupContainer.getParent().
                getPartGuid(),
                "");
        String partParentGuid = testPartInRun.getPartGuid()
                + testPartInRun.getParent().getPartGuidLongFromChild().replaceAll(
                testPartInRun.getParent().getPartGuid(),
                "");
        String partParentName = testPartInRun.getPartName();
        String partParentParentGuid = testPartInRun.getParent().getPartGuidLongFromChild();
        StepContainer curParent = (StepContainer) testPartInRun.getParent();
        ThreeDResultsMatrix ourParentMatrix =
                curParent.getResultMatrix();

        if (testPartInRun.getTestPartList().isEmpty()) { // This means had no childs so reflect the latest result
            // as it was

            Byte res = 2; // Because we log this when there is no childs.
            NotificationSubjectSingleton.getInstance().notifyLogMessages(
                    partParentName,
                    AtofLogLevel.INFO,
                    TestStringConstants.getEmptyTestContainerString(),
                    partParentGuid);
            NotificationSubjectSingleton.getInstance().notifyLogHeaderMessages(
                    Integer.parseInt(
                    testPartInRun.getPartId()),
                    testPartInRun.getContainerType().ordinal(),
                    res,
                    partParentParentGuid,
                    partParentName,
                    partParentGuid,
                    ExecutionGuidProvider.createInstance().
                    getExistingExecId());
            ourParentMatrix.setResultIn3dArray(curParent.getInvocationCountIndex(),
                    curParent.getTestPartList().
                    indexOf(testPartInRun),
                    curParent.getTestCaseDataIndex(),
                    testPartInRun.getTestPartResult());

        } else {
            if (!testPartInRun.getFailedConditions().isEmpty()) {
                testPartInRun.getParent().andTestPartResult(
                        testPartInRun.getTestPartResult());
                Byte res = 3; // Log 3 when condition fails..
                NotificationSubjectSingleton.getInstance().notifyLogMessages(
                        partParentName,
                        AtofLogLevel.INFO,
                        TestStringConstants.getConditionFailedString() + "\n"
                        + testPartInRun.getFailedConditions().toString(),
                        partParentGuid);
                NotificationSubjectSingleton.getInstance().notifyLogHeaderMessages(
                        Integer.parseInt(
                        testPartInRun.getPartId()),
                        testPartInRun.getContainerType().ordinal(),
                        res,
                        partParentParentGuid,
                        partParentName,
                        partParentGuid,
                        ExecutionGuidProvider.createInstance().
                        getExistingExecId());
                ourParentMatrix.setResultIn3dArray(curParent.getInvocationCountIndex(),
                        curParent.getTestPartList().
                        indexOf(testPartInRun),
                        curParent.getTestCaseDataIndex(),
                        testPartInRun.getTestPartResult());
            } else {
                validateFinalMatrix(stepGroupContainer);
            }
        }
        stepGroupContainer.resetCaseIndexes();
        
        NotificationSubjectSingleton.getInstance().notifyLogMessages(
                partParentName,
                AtofLogLevel.INFO,
                TestStringConstants.getEndedExecutionString(),
                partParentGuid);

        stepGroupContainer.setInvocationCountIndex(0); // Reset Count index just
        // after final Test Step Group validation for future Test Case invoations.

        boolean continueNextCase =
                driveValidationResult(testPartInRun,
                testIterInRun,
                mode);



        if (continueNextCase) {

            boolean logTheResultToParent = false;
            Short zero = 0;

            int retryCount = stepGroupContainer.getRetryCount();
            int retryOnFailCount = stepGroupContainer.getRetryOnFailCount();

            boolean breakTheLoop = false;
            if (!stepGroupContainer.getTestPartResult()) {
                if (retryCount < retryOnFailCount) {
                    stepGroupContainer.setRetryCount(retryCount + 1);

                    testIterInRun.previous();


                    NotificationSubjectSingleton.getInstance().notifyLogMessages(
                            stepGroupContainer.getPartName(),
                            AtofLogLevel.INFO,
                            "Test Step Group validation failed so retrying. Max Retry Count: "
                            + String.valueOf(retryOnFailCount)
                            + " Current Retry Count: "
                            + String.valueOf(retryCount),
                            tsgGuid);
                } else {
                    stepGroupContainer.setRetryCount(zero);
                    logTheResultToParent = true;
                    if (stepGroupContainer.getIsCritical()) {
                        breakTheLoop = true;
                    }
                }
            } else {
                stepGroupContainer.setRetryCount(zero);
                logTheResultToParent = true;
            }
            if (logTheResultToParent) {
                stepGroupContainer.getParent().andTestPartResult(
                        stepGroupContainer.getTestPartResult());
            }
            if (breakTheLoop) {
                NotificationSubjectSingleton.getInstance().notifyLogMessages(
                        stepGroupContainer.getPartName(),
                        AtofLogLevel.INFO,
                        " is a critical Test Step Group and failed so skipping remaining",
                        tsgGuid);
                return false;
            }


        }
        return true;
    }

    @Override
    protected void validateFinalMatrix(StepContainer refCur) {

        boolean finalResult = true;

        finalResult = refCur.validateThreeDResultArray();
        if (refCur.getContainerType()
                == AtofEnumaration.TestPartType.TestStepGroup) {
            // In case it was a TestStepGroup Result it must be
            // added to the parent Test Case result set for future validation
            Pair<TestStepDataObject, Boolean> resPair =
                    new Pair<TestStepDataObject, Boolean>(null,
                    finalResult);
            StepContainer curParent = (StepContainer) refCur.getParent();
            refCur.getCaseResultSet().put(curParent.getTestCaseDataIndex(),
                    resPair);

            ThreeDResultsMatrix ourParentMatrix =
                    curParent.getResultMatrix();



            ourParentMatrix.setResultIn3dArray(curParent.getInvocationCountIndex(),
                    curParent.getTestPartList().
                    indexOf(refCur),
                    curParent.getTestCaseDataIndex(),
                    finalResult);


        }
        refCur.setTestPartResult(finalResult);

    }

    @Override
    public boolean validatePartResult(TestIterator testIterInRun,
            DebuggingMode mode,
            boolean partResult) {
        boolean finalValidation = false;
        StepContainer stepGroupContainer = (StepContainer) testPartInRun;
        waitAsyncSteps(stepGroupContainer);

        boolean impossibleSuccess = false;
        try {
            stepGroupContainer.validateCurrentThreeDResultArray(stepGroupContainer.getActivateImpossibleSuccessPercFeature());
        } catch (ImpossibleToAchieveSuccessPercentageException ex) {
            impossibleSuccess = true;
        }
        String tsgGuidForIterations = stepGroupContainer.getPartGuidLongFromContainer()
                + stepGroupContainer.getParent().
                getPartGuidLongFromChild().replaceAll(stepGroupContainer.getParent().
                getPartGuid(),
                "");
        String tsgNameForIterations = stepGroupContainer.getPartNameLongFromContainer();

        String tsgGuidForMainContainer = stepGroupContainer.getPartGuid()
                + stepGroupContainer.getParent().
                getPartGuidLongFromChild().replaceAll(stepGroupContainer.getParent().
                getPartGuid(),
                "");

        String tsgNameForMainContainer = stepGroupContainer.getPartName();

        if (!impossibleSuccess) {


            if (stepGroupContainer.getRetryCaseWithOtherData() == true) {
                stepGroupContainer.setRetryCaseWithOtherData(false);
                testIterInRun.previous();
                NotificationSubjectSingleton.getInstance().notifyLogMessages(
                        tsgNameForMainContainer,
                        AtofLogLevel.INFO,
                        "Test Step Group iterated back to it self because there "
                        + "is more data to be applied to the case",
                        tsgGuidForMainContainer);
                NotificationSubjectSingleton.getInstance().notifyLogMessages(
                        tsgNameForIterations,
                        AtofLogLevel.INFO,
                        TestStringConstants.getEndedExecutionString(),
                        tsgGuidForIterations);

            } else {

                if (stepGroupContainer.getTestPartList().isEmpty()) {


                    finalValidation = true;

                } else {

                    NotificationSubjectSingleton.getInstance().notifyLogMessages(
                            tsgNameForIterations,
                            AtofLogLevel.INFO,
                            TestStringConstants.getValidatingChildTestStepstoTSGString(),
                            tsgGuidForIterations);

                    validateTestCase(stepGroupContainer);
                    
                    NotificationSubjectSingleton.getInstance().notifyLogMessages(
                            tsgNameForIterations,
                            AtofLogLevel.INFO,
                            TestStringConstants.getEndedExecutionString(),
                            tsgGuidForIterations);

                    stepGroupContainer.setInvocationCountIndex(stepGroupContainer.getInvocationCountIndex() + 1);
                    stepGroupContainer.resetCaseResults();
                    if (stepGroupContainer.getInvocationCountIndex()
                            < stepGroupContainer.getInvocationCount()) {
                        testIterInRun.previous();
                        NotificationSubjectSingleton.getInstance().notifyLogMessages(
                                tsgNameForMainContainer,
                                AtofLogLevel.INFO,
                                "TestPart iterated back to it self because there "
                                + "is more invocations to be applied to the case",
                                tsgGuidForMainContainer);



                    } else {
                        finalValidation = true;
                    }
                }

            }
        } else {
            NotificationSubjectSingleton.getInstance().notifyLogMessages(
                            tsgNameForIterations,
                            AtofLogLevel.INFO,
                            TestStringConstants.getValidatingChildTestStepstoTSGString(),
                            tsgGuidForIterations);

            validateTestCase(stepGroupContainer);
            
            NotificationSubjectSingleton.getInstance().notifyLogMessages(
                    tsgNameForIterations,
                    AtofLogLevel.INFO,
                    TestStringConstants.getEndedExecutionString(),
                    tsgGuidForIterations);
            finalValidation = true;
            stepGroupContainer.resetCaseResults();
            stepGroupContainer.setRetryCaseWithOtherData(false);
            stepGroupContainer.setInvocationCountIndex(stepGroupContainer.getInvocationCountIndex());
        }
        return finalValidation;

    }

    @Override
    protected boolean validateIfToContinue(boolean partResult) {
        return true;

    }
}
